home *** CD-ROM | disk | FTP | other *** search
- //---------------------------------------------------------------------------
- // FixDS.c
- //---------------------------------------------------------------------------
- // Changes the function prologs for all FAR functions in a Windows
- // application .EXE file to begin with "mov ax, ss".
- // Since SS == DS in an application, this is all that is need for any FAR
- // function. This eliminates the need for the EXPORTS and MakeProcInstance()
- // nonsense that Windows programmers have had to fuss with all these years.
- //---------------------------------------------------------------------------
- // Version 2.2, February 1990
- // Removed -d option.
- // Version 2.1, May 1989
- // Added -d option for special DGROUP hack.
- // Version 2.0, February 1989
- // Changed it to operate on the .EXE file instead of .OBJ files for
- // better reliability.
- //---------------------------------------------------------------------------
- // Public domain software
- // Written by Michael Geary
- //---------------------------------------------------------------------------
-
- #include <dos.h>
- #include <fcntl.h>
- #include <malloc.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define NEAR near
- #define FAR far
- #define VOID void
-
- typedef char CHAR;
- typedef unsigned char BYTE;
- typedef short SHORT;
- typedef unsigned short USHORT;
- typedef int INT;
- typedef unsigned int UINT;
- typedef long LONG;
- typedef unsigned long ULONG;
- typedef int HFILE;
-
- typedef CHAR NEAR * NPCHAR;
- typedef BYTE NEAR * NPBYTE;
- typedef SHORT NEAR * NPSHORT;
- typedef USHORT NEAR * NPUSHORT;
- typedef INT NEAR * NPINT;
- typedef UINT NEAR * NPUINT;
- typedef LONG NEAR * NPLONG;
- typedef ULONG NEAR * NPULONG;
- typedef VOID NEAR * NPVOID;
-
- typedef CHAR FAR * PCHAR;
- typedef BYTE FAR * PBYTE;
- typedef SHORT FAR * PSHORT;
- typedef USHORT FAR * PUSHORT;
- typedef INT FAR * PINT;
- typedef UINT FAR * PUINT;
- typedef LONG FAR * PLONG;
- typedef ULONG FAR * PULONG;
- typedef VOID FAR * PVOID;
-
- typedef UINT BOOL;
- typedef UINT FIELD;
-
- typedef CHAR SZ;
- typedef NPCHAR NPSZ;
- typedef PCHAR PSZ;
-
- #define TRUE 1
- #define FALSE 0
-
- #define loop for(;;)
-
- //---------------------------------------------------------------------------
-
- typedef struct _NEWEXE
- {
- USHORT magic;
- USHORT versionLink;
- USHORT offEntryTbl;
- USHORT cbEntryTbl;
- ULONG crc32;
- USHORT flags;
- USHORT dgroup;
- USHORT cbHeap;
- USHORT cbStack;
- ULONG cs_ip;
- ULONG ss_sp;
- USHORT nSegs;
- USHORT nModuleRefs;
- USHORT cbNonResNames;
- USHORT offSegTbl;
- USHORT offResourceTbl;
- USHORT offResNameTbl;
- USHORT offModuleRefTbl;
- USHORT offImportNameTbl;
- LONG offNonResNameTbl;
- USHORT nMovableEntries;
- USHORT shiftcountSector;
- USHORT nResourceSegs;
- USHORT offSegCksums;
- USHORT offReturnThunks;
- USHORT offSegRefBytes;
- USHORT nkSwapSize;
- USHORT versionApp;
- }
- NEWEXE;
-
- typedef NEWEXE NEAR * NPNEWEXE;
- typedef NEWEXE FAR * PNEWEXE;
-
- //---------------------------------------------------------------------------
-
- typedef struct _SEGINFO
- {
- USHORT sectorFile;
- USHORT cbFile;
- struct
- {
- FIELD segtype:3;
- FIELD otherflags:5;
- } flags;
- USHORT cbAlloc;
- }
- SEGINFO;
-
- typedef SEGINFO NEAR * NPSEGINFO;
- typedef SEGINFO FAR * PSEGINFO;
-
- // Values for seginfo.flags.type:
-
- #define CODETYPE 0
- #define DATATYPE 1
-
- //---------------------------------------------------------------------------
-
- VOID FileReadAt( HFILE hf, LONG lPosition, PVOID pData, USHORT cbData );
- VOID FileSeekTo( HFILE hf, LONG lPosition );
- VOID FileWriteAt( HFILE hf, LONG lPosition, PVOID pData, USHORT cbData );
- SHORT PatchSeg( PBYTE pMem, USHORT cbSeg );
-
- //---------------------------------------------------------------------------
-
- VOID cdecl main
- (
- SHORT nArgs,
- NPCHAR npArgs[]
- )
- {
- HFILE hfEXE;
- PBYTE pMem;
- SHORT nChanges, nTotalChanges;
- BYTE oldexe[0x40];
- NEWEXE newexe;
- NPSEGINFO npseginfo, npseginfoBase;
- LONG loffNewExe, loffSeg;
- USHORT nSeg, cbSegTbl, cbSeg;
-
- // Check for presence of single file name
-
- if( nArgs != 2 )
- {
- printf( "FixDS: Missing or extra parameter\n" );
- exit(1);
- }
-
- // Convert name to upper case for messages
-
- strupr( npArgs[1] );
-
- // Open the file, read and check old EXE header
-
- if( _dos_open( npArgs[1], (int)O_BINARY | O_RDWR, &hfEXE ) )
- {
- printf( "FixDS: Cannot open %s\n", npArgs[1] );
- exit(2);
- }
-
- FileReadAt( hfEXE, 0L, oldexe, sizeof(oldexe) );
-
- if( *(PUSHORT)&oldexe[0] != 0x5A4D )
- {
- printf( "FixDS: %s is not an EXE file\n", npArgs[1] );
- exit(3);
- }
-
- if( *(PUSHORT)&oldexe[0x18] != 0x40 )
- {
- printf( "FixDS: %s is not a Windows EXE file\n", npArgs[1] );
- exit(4);
- }
-
- // Read new EXE header
-
- loffNewExe = *(PLONG)&oldexe[0x3C];
-
- FileReadAt( hfEXE, loffNewExe, &newexe, sizeof(newexe) );
-
- if( newexe.magic != 0x454E )
- {
- printf( "FixDS: %s is not a Windows EXE file\n", npArgs[1] );
- exit(5);
- }
-
- // Allocate and read segment table
-
- cbSegTbl = newexe.nSegs * sizeof(SEGINFO);
- npseginfoBase = npseginfo = malloc( cbSegTbl );
- if( ! npseginfo )
- {
- printf( "FixDS: Cannot allocate memory for segment table\n" );
- exit(6);
- }
-
- FileReadAt( hfEXE, loffNewExe + newexe.offSegTbl, npseginfo, cbSegTbl );
-
- // Allocate 64K buffer for code segments, using DOS call to make sure
- // it's a true segment address (offset = 0).
-
- FP_OFF(pMem) = 0;
- if( _dos_allocmem( 0x1000, &FP_SEG(pMem) ) )
- {
- printf( "FixDS: Cannot allocate memory for segment buffer\n" );
- exit(7);
- }
-
- // Now read each segment and patch it
-
- nTotalChanges = 0;
-
- for( nSeg = 1; nSeg <= newexe.nSegs; nSeg++, npseginfo++ )
- {
- switch( npseginfo->flags.segtype )
- {
- case CODETYPE:
- cbSeg = npseginfo->cbFile;
- if( ! cbSeg )
- cbSeg = 0xFFFF; // we can round 64K down to 65535
-
- loffSeg = (ULONG)npseginfo->sectorFile << newexe.shiftcountSector;
-
- FileReadAt( hfEXE, loffSeg, pMem, cbSeg );
-
- nChanges = PatchSeg( pMem, cbSeg );
- nTotalChanges += nChanges;
-
- if( nChanges )
- FileWriteAt( hfEXE, loffSeg, pMem, cbSeg );
- break;
- }
- }
-
- // Close the file, report changes, and exit
-
- if( _dos_close( hfEXE ) )
- {
- printf( "FixDS: Error closing %s\n", npArgs[1] );
- exit(8);
- }
-
- printf( "FixDS: Fixed up %d FAR functions\n", nTotalChanges );
- exit(0);
- }
-
- //---------------------------------------------------------------------------
- // Read data from a file at a given offset
- //---------------------------------------------------------------------------
-
- VOID FileReadAt
- (
- HFILE hf,
- LONG lPosition,
- PVOID pData,
- USHORT cbData
- )
- {
- UINT cbResult;
-
- FileSeekTo( hf, lPosition );
-
- if( _dos_read( hf, pData, cbData, &cbResult ) ||
- cbResult != cbData )
- {
- printf( "FixDS: Read Failed\n" );
- exit(11);
- }
- }
-
- //---------------------------------------------------------------------------
- // Seek a file to a given offset from the start.
- //---------------------------------------------------------------------------
-
- VOID FileSeekTo
- (
- HFILE hf,
- LONG lPosition
- )
- {
- union REGS r;
-
- r.x.ax = 0x4200; // Seek to absolute position
- r.x.bx = hf;
- r.x.cx = (USHORT)( lPosition >> 16 );
- r.x.dx = (USHORT)( lPosition );
-
- intdos( &r, &r );
-
- if( r.x.cflag )
- {
- printf( "FixDS: Seek Failed\n" );
- exit(10);
- }
- }
-
- //---------------------------------------------------------------------------
- // Write data to a file at a given offset.
- //---------------------------------------------------------------------------
-
- VOID FileWriteAt
- (
- HFILE hf,
- LONG lPosition,
- PVOID pData,
- USHORT cbData
- )
- {
- UINT cbResult;
-
- FileSeekTo( hf, lPosition );
-
- if( _dos_write( hf, pData, cbData, &cbResult ) ||
- cbResult != cbData )
- {
- printf( "FixDS: Write Failed\n" );
- exit(12);
- }
- }
-
- //---------------------------------------------------------------------------
- // Find and patch all FAR function prologs. These begin with either:
- //
- // 0x1E push ds
- // 0x58 pop ax
- //
- // or:
- //
- // 0x8C mov ax, ds
- // 0xD8 "
- //
- // or:
- //
- // 0x90 nop
- // 0x90 nop
- //
- // followed by:
- //
- // 0x90 nop
- // 0x45 inc bp
- // 0x55 push bp
- // 0x8B mov bp, sp
- // 0xEC "
- // 0x1E push ds
- // 0x8E mov ds, ax
- // 0xD8 "
- //
- // Change the first two bytes of each FAR function to:
- //
- // 0x8C mov ax, ss
- // 0xD0 ...
- //---------------------------------------------------------------------------
-
- SHORT PatchSeg
- (
- PBYTE pMem,
- USHORT cbSeg
- )
- {
- SHORT nChanges;
- PUSHORT p, pEnd;
-
- nChanges = 0;
-
- for( p = (PUSHORT)pMem, pEnd = (PUSHORT)(pMem + cbSeg - 10);
- p < pEnd;
- p = (PUSHORT)( (PBYTE)p + 1 ) )
- {
- if( ( p[0] == 0x581E || p[0] == 0xD88C ) &&
- p[1] == 0x4590 &&
- p[2] == 0x8B55 &&
- p[3] == 0x1EEC &&
- p[4] == 0xD88E )
- {
- nChanges++;
- p[0] = 0xD08C; // mov ax, ss
- }
- }
-
- return nChanges;
- }
-
- //---------------------------------------------------------------------------
-
-